DTS
根据硬件工程师给出的信息,这颗 GSensor 接到 Spi0 上,我们可以看一下 DTS 中的信息:
1 |
|
SPI 部分驱动
这种 SPI 类的 Sensor 一般会将驱动分为两个部分,一部分是 CHIP_spi.c 一部分是 CHIP.c。
CHIP_spi.c
CHIP_spi_driver
在 CHIP_SPI.c 中完成的任务是 CHIP_spi_read 及 CHIP_spi_write 等回调函数的实现。
SPI 协议驱动有些类似平台设备驱动:
1 | static struct spi_driver ad714x_spi_driver = { |
module_spi_driver() 宏
内核将调用 module_spi_driver() 这个宏来注册和卸载 spi 设备,这个 module_spi_driver 是专门针对于 spi 架构定义的。
在 include/linux/spi/spi.h 中,我们可以看到:
1 | 281 /** |
可以还可以往下去追看 module_driver() 这个宏 ,它将 spi_register/unregister_driver() 与 module_init 和 module_exit 封装了起来。所以说实际上 module_spi_driver() 和 module_init/exit 几乎是没有区别的。
之所以直接将其封装的原因是因为这个 SPI 设备本身是不可插拔的,也就不需要 init 和 exit 的过程,系统上电就直接注册了。
CHIP_spi_probe()
1 | static int ad714x_spi_probe(struct spi_device *spi) |
抽象出来就是
1 | static int __devinit CHIP_spi_probe(struct spi_device *spi) |
其中的主 probe 放到后面去分析。
其中的 spi_setup() 中可以修改 spi_device 特征,如传输模式、字长或时钟速率。
CHIP_spi_read / CHIP_spi_write
先介绍一下 struct spi_message
1 | 789 struct spi_message { |
一个 message 是一次数据交换的原子请求, spi_message 是多个 spi_transfer 结构组成,这些 spi_transfer 通过一个链表 transfers 组织在一起。具体可以看这篇博文:SPI 数据传输的队列化。
spi_message 结构有一个链表头字段 transfers。
spi_transfer 结构包含一个链表头字段 transfer_list。
通过这两个链表头字段,所有属于这次 message 传输的 transfer 都会挂在 spi_messages.transfers 下。
我们通过 spi_message_add_tail 来向 spi_message 结构中添加一个 spi_transfer 结构。
然后调用 spi_async 同步 或者 spi_sync 异步来发起一个 message 传输请求,通常 spi_async 或 spi_sync 由将被封装在 read 和 write 中。
1 | //read 有四个参数 |
1 | // 三个参数 |
CHIP.c
之前我们在 CHIP_spi_probe() 中可以注意到,有如下代码
1 | chip = ad714x_probe(&spi->dev, BUS_SPI, spi->irq, |
这里 CHIP_probe() 的定义在 CHIP.c
我们来读一下 CHIP_probe() 的代码
1 | // 有 5 个参数 |
参考:
- 内核源码 /kernel/driver/spi/spi.c spi.h
- 这个没有纠结于代码实现,归纳了Linux内核对 SPI 的支持方法。还有抽象出来说如何实现 SPI 驱动: http://linux.it.net.cn/m/view.php?aid=18852
- 这个以 一个 eeprom 的代码来进行分析 SPI 总线 http://www.cnblogs.com/jason-lu/p/3165327.html